/*
 * $Header: $
 * $Id$
 *
 * Copyright (c) 2011, Michael DePhillips. All Rights Reserved.
 * This code may not be used without the express written permission
 * of the copyright holder, Michael DePhillips.
 */

package com.facebook.bannermaker.android.activity.template;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Vector;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.widget.ListView;

import com.facbook.bannermaker.android.util.ActivityUtil;
import com.facebook.android.DialogError;
import com.facebook.android.Facebook;
import com.facebook.android.FacebookError;
import com.facebook.android.SessionStore;
import com.facebook.android.Facebook.DialogListener;
import com.facebook.bannermaker.android.R;
import com.facebook.bannermaker.android.util.AppConstants;
import com.facebook.bannermaker.android.util.ImageCache;
import com.google.android.apps.analytics.GoogleAnalyticsTracker;

/**
 * Activity for how to display the banners in a list view
 *
 * @author Michael DePhillips
 * 
 */
public class MakeBannerTemplateActivity extends ListActivity {

	// Facebook SDK related variables
    private static final String APP_ID = "212393005452204";
    public Facebook m_facebook = new Facebook(APP_ID);
    protected List<Bitmap> m_bitmaps = new Vector<Bitmap>();
    protected String m_id = null;
    private String m_name = null;

    //Inner class reference
    private ListView m_listView;
    private List<String> m_groupNames = new Vector<String>();
    protected List<Bitmap> m_banners = new Vector<Bitmap>();
    protected List<String> m_urls = new Vector<String>();
    private BannerObjectListAdaptor m_bannerAdapter;
    private GroupObjectListAdaptor m_groupAdapter;
    protected static ImageCache m_FileCache = null;

    GoogleAnalyticsTracker tracker;
    
    // inner class references
    protected JSONArray m_groupsArray = null;
    private boolean m_inBannerView = false;
    private boolean m_bannerClicked = false;
    private int m_bannerClickedPosition = 0;       

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE); 
        setContentView(R.layout.banner_maker_template);  

        // get templates
        new getTemplateJson().execute();
        
        // load google analytics
        tracker = GoogleAnalyticsTracker.getInstance();

        // Start the tracker in manual dispatch mode... 
        tracker.startNewSession(AppConstants.GOOGLE_ANALYTICS_CODE, this);        

        // get cache
        if (m_FileCache == null) {
            m_FileCache = new ImageCache(this, 25, 5);            
        }
    }

    /**
     * Create and show all the images in a ScrollView.
     */
    private void createUI() {

        //        String[] assets = null; 
        //        //InputStream is = null;
        //        try {
        //            //is = this.getResources().getAssets().open("Templates/test_banner.jpg");
        //            assets = this.getResources().getAssets().list("Templates");
        //
        //            // prepare the listview with group names
        //            for( int i = 0; i < assets.length; i++ ) {
        //                m_groupNames.add(assets[i].toUpperCase());
        //            }
        //            m_groupAdapter = new GroupObjectListAdaptor(m_groupNames, this);            
        //            m_listView = getListView();
        //            m_listView.setAdapter(m_groupAdapter);
        //
        //        } catch (IOException e) {
        //            ;
        //        }

        //Bitmap image = BitmapFactory.decodeStream(is);

        // prepare the listview with group names
        for( int i = 0; i < m_groupsArray.length(); i++ ) {
            try {
                m_groupNames.add(m_groupsArray.getJSONObject(i).getString(AppConstants.JSON_GROUPS_NAME).toUpperCase());
            } catch (JSONException e) {
                AlertDialog alert = ActivityUtil.getAlertOkDialogue(MakeBannerTemplateActivity.this, e.toString());
                alert.show();
            }
        }

        m_groupAdapter = new GroupObjectListAdaptor(m_groupNames, this);            
        m_listView = getListView();
        m_listView.setAdapter(m_groupAdapter);
    }

    /**
     * Based on which object is clicked, either open the folder or download the
     * object.
     */
    @Override
    public void onListItemClick(ListView parent, View v, int position, long id) {

        if( m_inBannerView ) {
            if( !m_bannerClicked ) {
                // remember what banner was clicked for this object 
                m_bannerClicked = true;
                m_bannerClickedPosition = position;
                
            	// register the user clicked the button
                tracker.trackEvent(
                		"Banner",  // Category
                        "Click",  // Action
                        m_urls.get(position), // Label
                        25);       // Value
                
                tracker.dispatch();

                // try to restore session
                if( SessionStore.restore(m_facebook, this) ) {
                    trySessionRestore();
                }
                else {
                    tryFacebookLogin();
                }
            }
        }
        else {

            // recycle old bitmaps and reload the new ones
            m_banners = new Vector<Bitmap>();
            m_urls = new Vector<String>();
            System.gc();

            String groupNameClicked = m_groupNames.get(position);            
            new DownloadAndDisplayImage(groupNameClicked).execute();

            m_inBannerView = true;
        }
    }

    /**
     * Post to xxxxx's wall yes/no listener
     */
    DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            switch (which){
            case DialogInterface.BUTTON_POSITIVE:

                final int WIDTH = 98;
                final int HEIGHT = 66;

                // export and upload photos
                // get the five images to upload
                Bitmap bannerSelected = m_banners.get(m_bannerClickedPosition);
                // first in last out of scaled banner images
                //recycleBitmaps();

                for(int i = 0; i < 5; i++) {                    
                    m_bitmaps.add(0, Bitmap.createBitmap(bannerSelected, i * WIDTH, 0, WIDTH, HEIGHT));
                }

                new FacebookUploadAndTagPhoto(1).execute();  
                break;

            case DialogInterface.BUTTON_NEGATIVE:
                new FacebookUserLogoff().execute();
                break;
            }
        }
    };

    /**
     * Clears bitmaps and frees up memory
     */
    public void recycleBitmaps() {
        for(int i = 0; i < m_banners.size(); i++ ) {
            m_banners.get(i).recycle();
        }
        for(int i = 0; i < m_bitmaps.size(); i++ ) {
            m_bitmaps.get(i).recycle();
        }
        m_banners = new Vector<Bitmap>();
        System.gc();
    }


    /**
     * Try restoring session for ease of banner posting
     */
    private void trySessionRestore() {
        // sets username and user id
        m_name = SessionStore.restoreName(this);
        m_id = SessionStore.restoreId(this);            

        // yes/no dialog to verify user wants to post the banner
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage("Post to " + m_name + "?").setPositiveButton("Yes", dialogClickListener)
        .setNegativeButton("No", dialogClickListener).show(); 
    }

    /**
     * Tries to login to Facebook with app dialog
     */
    private void tryFacebookLogin() {
        m_facebook.authorize(MakeBannerTemplateActivity.this, new String[] { AppConstants.JSON_PUBLISH_STREAM, AppConstants.JSON_PUBLISH_PHOTOS }, Facebook.FORCE_DIALOG_AUTH, new DialogListener() {

            public void onComplete(Bundle values) {

                // obtain user's full name and member identification number for posting photos
                try {
                    String response = m_facebook.request(AppConstants.JSON_ME);
                    JSONObject jsonObj;
                    try {
                        jsonObj = new JSONObject(response);
                        m_id = jsonObj.getString(AppConstants.JSON_ME_ID);
                        m_name = jsonObj.getString(AppConstants.JSON_ME_NAME);                                
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                // save session for user and try posting the photos
                SessionStore.save(m_facebook, MakeBannerTemplateActivity.this, m_name, m_id);                
                trySessionRestore();  
            }

            /**
             * Print Facebook Error in Alert Dialog
             */
            public void onFacebookError(FacebookError error) {
                String errorMsg = error.toString();  
                AlertDialog alert = ActivityUtil.getAlertOkDialogue(MakeBannerTemplateActivity.this, errorMsg);
                alert.show();
            }    

            /**
             * Print Dialog Error in Alert Dialog            
             */
            public void onError(DialogError e) {
                String errorMsg = e.toString();
                AlertDialog alert = ActivityUtil.getAlertOkDialogue(MakeBannerTemplateActivity.this, errorMsg);
                alert.show();
            }    

            public void onCancel() {}

        });   
    }

    // upload and tag user in the 5 created photos
    public void onPostToFacebookClicked(View v) {

        // try to restore session
        if( SessionStore.restore(m_facebook, this) ) {
            trySessionRestore();
        }
        else {
            tryFacebookLogin();
        }
    }

    //this is called when the screen rotates.
    // (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
    @Override
    public void onConfigurationChanged(Configuration newConfig)
    {
        super.onConfigurationChanged(newConfig);        
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK)) {
            if( m_inBannerView ) {
                m_listView = getListView();
                m_listView.setAdapter(m_groupAdapter);
                m_inBannerView = false;
            }
            else {
                // return to previous activity
                finish();
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    /**
     * Tries to upload and tag photos
     */
    private class FacebookUploadAndTagPhoto extends AsyncTask<Void, String, Boolean> {

        private ProgressDialog progressDialogue = new ProgressDialog(MakeBannerTemplateActivity.this);
        private String errorMsg = null;
        private int photoNum;

        public FacebookUploadAndTagPhoto(int aPhotoNum) {
            super();
            photoNum = aPhotoNum;
        }

        /*
         * Display progress dialogue
         */
        @Override
        protected void onPreExecute() {            
            progressDialogue.setMessage("Uploading photo " + photoNum + " of 5...");
            progressDialogue.show();
        }

        /*
         * Try to upload and tag photo through facebook
         */
        @Override
        protected Boolean doInBackground(Void... param) {

            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            m_bitmaps.get(photoNum-1).compress(Bitmap.CompressFormat.JPEG, 100, stream);                
            byte[] imageBytes = stream.toByteArray();

            // add all the information to send an upload and tag photo request
            Bundle params = new Bundle();                
            params.putString(Facebook.TOKEN, m_facebook.getAccessToken());                                         
            params.putByteArray(AppConstants.JSON_PICTURE, imageBytes);

            // add self tag
            JSONObject tags = new JSONObject();                
            try {
                tags.put(AppConstants.JSON_TAG_UID, m_id);
                tags.put(AppConstants.JSON_TAG_POSITION_X, 1);
                tags.put(AppConstants.JSON_TAG_POSITION_Y, 1);
            } catch (JSONException e) {
                errorMsg = e.toString();
            }
            JSONArray tagsArray = new JSONArray();
            tagsArray.put(tags);

            params.putString(AppConstants.JSON_TAGS, tagsArray.toString());

            String response = null;
            // try sending the request
            try {
                response = m_facebook.request(AppConstants.JSON_METHOD_UPLOAD_PHOTO, params, AppConstants.JSON_POST);
            } catch (FileNotFoundException e) {
                errorMsg = e.toString();
            } catch (MalformedURLException e) {
                errorMsg = e.toString();
            } catch (IOException e) {
                errorMsg = e.toString();
            }

            // recycle bitmap created
            m_bitmaps.get(photoNum-1).recycle();

            return Boolean.valueOf(errorMsg == null);
        }

        /**
         * Can use UI thread here.
         */
        @Override
        protected void onPostExecute(Boolean result) {

            if (progressDialogue.isShowing()) {
                progressDialogue.dismiss();
            }

            // Display error dialogue if you can't authenticate
            if (result.booleanValue() == false) {
                AlertDialog alert = ActivityUtil.getAlertOkDialogue(MakeBannerTemplateActivity.this, errorMsg);
                alert.show();
            } else {
                if( photoNum == 5 ) {
                    recycleBitmaps();
                    AlertDialog alert = ActivityUtil.getAlertOkFinishDialogue(MakeBannerTemplateActivity.this, "Upload Successful!");
                    alert.show();
                }
                else {
                    new FacebookUploadAndTagPhoto(photoNum+1).execute(); 
                }
            }
        }
    }

    /**
     * Tries to logoff user
     */
    private class FacebookUserLogoff extends AsyncTask<Void, Void, Boolean> {

        private ProgressDialog progressDialogue = new ProgressDialog(MakeBannerTemplateActivity.this);
        private boolean status = false;
        private String errorMsg = null;

        public FacebookUserLogoff() {
            super();
        }

        /*
         * Display progress dialogue
         */
        @Override
        protected void onPreExecute() {
            progressDialogue.setMessage(MakeBannerTemplateActivity.this.getString(R.string.label_logging_off));
            progressDialogue.show();
        }

        /*
         * Try to logoff of current Facebook user
         */
        @Override
        protected Boolean doInBackground(Void... param) {
            // logout of Facebook user
            try {
                m_facebook.logout(MakeBannerTemplateActivity.this);
                status = true;
            } catch (MalformedURLException e) {
                errorMsg = e.toString();
            } catch (IOException e) {
                errorMsg = e.toString();
            }

            return Boolean.valueOf(status);
        }

        /**
         * Can use UI thread here.
         */
        @Override
        protected void onPostExecute(Boolean result) {

            if (progressDialogue.isShowing()) {
                progressDialogue.dismiss();
            }

            // Display error dialogue if you can't authenticate
            if (result.booleanValue() == false) {
                AlertDialog alert = ActivityUtil.getAlertOkDialogue(MakeBannerTemplateActivity.this, errorMsg);
                alert.show();
            } else {
                // clear the session            
                SessionStore.clear(MakeBannerTemplateActivity.this);
                tryFacebookLogin();
            }
        }
    }

    /**
     * Get body content
     * @param input
     * @return
     * @throws IOException
     */
    protected static String getBodyContent(InputStream input) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(input));
        StringBuilder sb = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            throw e;
        } finally {
            try {
                input.close();
            } catch (IOException e) {
                throw e;
            }
        }
        return sb.toString();
    }

    /**
     * Tries to grab template image information off of website
     */
    private class getTemplateJson extends AsyncTask<Void, Void, Boolean> {

        private HttpGet m_httpGet = null;
        private DefaultHttpClient m_httpClient = new DefaultHttpClient();
        private ProgressDialog progressDialogue = new ProgressDialog(MakeBannerTemplateActivity.this);
        private boolean status = false;
        private String errorMsg = null;

        public getTemplateJson() {
            super();
        }

        /*
         * Display progress dialogue
         */
        @Override
        protected void onPreExecute() {
            progressDialogue.setMessage(MakeBannerTemplateActivity.this.getString(R.string.label_getting_templates));
            progressDialogue.show();
        }

        /*
         * Tries to grab template image information off of website
         */
        @Override
        protected Boolean doInBackground(Void... param) {
            // connect to template http file
            try {
                m_httpGet = new HttpGet(AppConstants.TEMPLATE_WEBSITE);
                m_httpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
                HttpResponse response = m_httpClient.execute(m_httpGet);

                // Read the response body.
                HttpEntity entity = response.getEntity();
                String body = getBodyContent(entity.getContent());
                JSONObject returnObj = new JSONObject(body);
                m_groupsArray = new JSONArray( returnObj.getString(AppConstants.JSON_GROUPS) );
                status = true;

            } catch (Exception e) {
                status=false;
                errorMsg = "Could not connect to server, please try again. " + e;
            }

            return Boolean.valueOf(status);
        }

        /**
         * Can use UI thread here.
         */
        @Override
        protected void onPostExecute(Boolean result) {

            if (progressDialogue.isShowing()) {
                progressDialogue.dismiss();
            }

            // Display error dialogue if you can't authenticate
            if (result.booleanValue() == false) {
                AlertDialog alert = ActivityUtil.getAlertOkDialogue(MakeBannerTemplateActivity.this, errorMsg);
                alert.show();
            } else {
                // load UI
                createUI();
            }
        }
    }
    
    @Override
    protected void onDestroy() {
      super.onDestroy();
      // Stop the tracker when it is no longer needed.
      tracker.stopSession();
    }

    /**
     * Tries to download and display an image
     */
    private class DownloadAndDisplayImage extends AsyncTask<Void, String, Boolean> {

        private ProgressDialog progressDialogue = new ProgressDialog(MakeBannerTemplateActivity.this);
        private String errorMsg = null;
        private String imageUrl = null;
        private Bitmap bitmap = null;

        public DownloadAndDisplayImage(String anImageUrl) {
            super();
            imageUrl = anImageUrl;
        }

        /*
         * Display progress dialogue
         */
        @Override
        protected void onPreExecute() {            
            progressDialogue.setMessage("Getting Banners...");
            progressDialogue.show();
        }

        /*
         * Try to upload and tag photo through facebook
         */
        @Override
        protected Boolean doInBackground(Void... param) {

            int timesTried = 0;
            int numAttempts = 3;

            // find the right array of links to download or display banners          
            JSONArray links = null;
            JSONObject obj = null;
            try {
                while( links == null ) {
                    obj = m_groupsArray.getJSONObject(timesTried);
                    if( imageUrl.toLowerCase().equals(obj.getString(AppConstants.JSON_GROUPS_NAME).toLowerCase())) {
                        links = obj.getJSONArray(AppConstants.JSON_GROUPS_LINKS);
                    }
                    timesTried++;
                }
            } catch (Exception e) {
                ;
            }

            // download and dispay banners
            for( int i = 0; i < links.length(); i++ ) {
                timesTried = 1;

                try {
                    imageUrl = links.getJSONObject(i).getString(AppConstants.JSON_GROUPS_URL);
                } catch (JSONException e1) {
                    errorMsg = "format error";
                }
                synchronized(m_FileCache) {
                    // find the image in the cache or download a new one
                    bitmap = m_FileCache.get(imageUrl);
    
                    if (bitmap == null) {
                        // fetch the image in the background
                        while (timesTried <= numAttempts) {
                            try {
                                URL url = new URL(imageUrl);
                                bitmap = BitmapFactory.decodeStream(url.openStream());
                                m_FileCache.put(imageUrl, bitmap);
                                break;
                            } catch (Throwable e) {
    
                                errorMsg = "Could Not Get Image From URL";
    
                                timesTried++;
                            }
                        }
                    } 
                }
                m_banners.add(bitmap);
                m_urls.add(imageUrl);
                timesTried = 1;                            
            }

            return Boolean.valueOf(timesTried <= numAttempts);
        }    
        
        

        /**
         * Can use UI thread here.
         */
        @Override
        protected void onPostExecute(Boolean result) {

            if (progressDialogue.isShowing()) {
                progressDialogue.dismiss();
            }
            // Display error dialogue if you can't authenticate
            if (result.booleanValue() == false) {
                AlertDialog alert = ActivityUtil.getAlertOkDialogue(MakeBannerTemplateActivity.this, errorMsg);
                alert.show();
            } else {
                m_bannerAdapter = new BannerObjectListAdaptor(m_banners, MakeBannerTemplateActivity.this);            
                m_listView = getListView();
                m_listView.setAdapter(m_bannerAdapter);            
                m_inBannerView = true; 
            }
        }
    }
}